﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Kinect.Framework.Interfaces;
using System.Windows.Controls;
using Microsoft.Expression.Controls;
using System.Windows;
using Kinect.Framework.Lib;
using System.Windows.Threading;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Controls.Primitives;
using System.Collections;

namespace Kinect.Framework.Controls
{

    public class KinectContextMenu : ListBox, IKinectElement
    {
        #region Events GotKinectFocused
        public delegate void GotKinectFocusedEventHandler(object s, PayloadEventArgs<IKinectElement> e);
        public event GotKinectFocusedEventHandler GotKinectFocused;
        public void OnGotKinectFocused(IKinectElement value)
        {
            if (GotKinectFocused != null)
                GotKinectFocused(this, new PayloadEventArgs<IKinectElement>(value));
        }
        #endregion

        #region Events LostKinectFocused
        public delegate void LostKinectFocusedEventHandler(object s, PayloadEventArgs<IKinectElement> e);
        public event LostKinectFocusedEventHandler LostKinectFocused;
        public void OnLostKinectFocused(IKinectElement value)
        {
            if (LostKinectFocused != null)
                LostKinectFocused(this, new PayloadEventArgs<IKinectElement>(value));
        }
        #endregion

        #region Events OnKinectItemSelected
        public delegate void OnKinectItemSelectedEventHandler(object s, PayloadEventArgs<IKinectElement> e);
        public event OnKinectItemSelectedEventHandler OnKinectItemSelected;
        public void OnOnKinectItemSelected(IKinectElement value)
        {
            if (OnKinectItemSelected != null)
            {
                Hide();
                OnKinectItemSelected(this, new PayloadEventArgs<IKinectElement>(value));
            }
        }
        #endregion
               

        #region IKinectElement Members

        public void GotKinectFocus(ManagedNite.XnMPoint point, ManagedNite.XnMPoint realPoint, System.Windows.UIElement OriginalSource)
        {
            dt.Stop();
            this.Visibility = System.Windows.Visibility.Visible;
            isFocused = true;
            OnGotKinectFocused(this);
        }

        public void LostKinectFocus()
        {
            if (!dt.IsEnabled)
            {
                dt = new DispatcherTimer();
                dt.Interval = TimeSpan.FromSeconds(1);
                dt.Tick += (s, e) =>
                {
                    Hide();
                };
                dt.Start();
            }

        }

        #endregion

        #region Radius
        /// <summary>
        /// The Radius Dependency
        /// </summary>
        public static readonly DependencyProperty RadiusProperty = DependencyProperty.RegisterAttached("Radius", typeof(int), typeof(KinectContextMenu), new FrameworkPropertyMetadata((int)200, new PropertyChangedCallback(OnRadiusChanged)));
        /// <summary>
        /// The Header of your item
        /// </summary>
        public int Radius
        {
            get { return (int)GetValue(KinectContextMenu.RadiusProperty); }
            set
            {
                SetValue(KinectContextMenu.RadiusProperty, value);
            }
        }
        /// <summary>
        /// Handles changes to the Radius property.
        /// </summary>
        private static void OnRadiusChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
        }
        #endregion

        private DispatcherTimer dt = new DispatcherTimer();
        private bool isFocused = false;

        public KinectContextMenu()
        {
        }

        static KinectContextMenu()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(KinectContextMenu), new FrameworkPropertyMetadata(typeof(KinectContextMenu)));
        }

        protected override DependencyObject GetContainerForItemOverride()
        {
            return new KinectContextMenuItem();
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            if (!KinectManipulation.IsDesignTime)
            {
                this.Visibility = System.Windows.Visibility.Collapsed;
                KinectWindow.GestureController(this).SteadyManipulationDetected += new Controller.KinectManipulationController.SteadyManipulationDetectedEventHandler(OnSteadyManipulationDetected);
            }
        }

        protected override void OnItemsSourceChanged(System.Collections.IEnumerable oldValue, System.Collections.IEnumerable newValue)
        {
            base.OnItemsSourceChanged(oldValue, newValue);
            int i = 0;
            int count = 0;
            IEnumerator enumerator = newValue.GetEnumerator();
            while (enumerator.MoveNext())
                count++;
            foreach (object itm in newValue)
            {
                var container = this.ItemContainerGenerator.ContainerFromItem(itm) as KinectContextMenuItem;
                container.GlobalOffsetX = Radius * Math.Cos(Math.PI * (360 / count) / 180 * i);
                container.GlobalOffsetY = Radius * Math.Sin(Math.PI * (360 / count) / 180 * i);
                i++;
            }
        }

        public void Hide()
        {
            this.IsHitTestVisible = false;
            dt.Stop();
            this.Visibility = System.Windows.Visibility.Collapsed;
            isFocused = false;
            OnLostKinectFocused(this);
        }

        void OnSteadyManipulationDetected(object s, Lib.PayloadEventArgs<KinectPointer> e)
        {
            if (!isFocused && IsEnabled)
            {
                this.IsHitTestVisible = true;
                isFocused = true;
                var content = GetTemplateChild("Content") as UIElement;
                Canvas.SetLeft(content, e.Payload.Position.X + (e.Payload.ActualWidth / 2));
                Canvas.SetTop(content, e.Payload.Position.Y + (e.Payload.ActualHeight / 2));
                var HitTestZone = GetTemplateChild("HitTestZone") as FrameworkElement;
                HitTestZone.Width = Radius * 2.5;
                HitTestZone.Height = Radius * 2.5;
                Canvas.SetLeft(HitTestZone, e.Payload.Position.X + (e.Payload.ActualWidth / 2) - Radius);
                Canvas.SetTop(HitTestZone, e.Payload.Position.Y + (e.Payload.ActualHeight / 2) - Radius);
                this.Visibility = System.Windows.Visibility.Visible;
            }
        }
    }
}
